﻿using System;
using System.Reflection;
using Castle.DynamicProxy;
using Wisdom.Core;

namespace Wisdom.Core
{
    /// <summary>
    /// 表示使用用代码进行初始化方式进行配置的配置源
    /// </summary>
    public sealed class CodeConfigSource : IConfigSource
    {
        #region Private Fields
        private readonly WisdomConfigSection config;
        #endregion

        #region Ctor
        /// <summary>
        /// 构造函数：实始化 <c>CodeConfigSource</c> 类.
        /// </summary>
        public CodeConfigSource()
        {
            config = new WisdomConfigSection
                {
                    Application = new ApplicationElement(),
                    Exceptions = new ExceptionElementCollection(),
                    Generators = new GeneratorElement
                            {
                                IdentityGenerator = new IdentityGeneratorElement(),
                                SequenceGenerator = new SequenceGeneratorElement()
                            },
                    ObjectContainer = new ObjectContainerElement(),
                    Interception = new InterceptionElement
                        {
                            Contracts = new InterceptContractElementCollection(),
                            Interceptors = new InterceptorElementCollection()
                        }
                };
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// 获取或设置 <see cref="IApplication"/> 实例.
        /// </summary>
        public Type Application
        {
            get { return Type.GetType(config.Application.Provider); }
            set { config.Application.Provider = value.AssemblyQualifiedName; }
        }
        /// <summary>
        /// 获取或设置自增长生成器类型
        /// </summary>
        public Type IdentityGenerator
        {
            get { return Type.GetType(config.Generators.IdentityGenerator.Provider); }
            set { config.Generators.IdentityGenerator.Provider = value.AssemblyQualifiedName; }
        }
        /// <summary>
        /// 获取或设置按顺序自增长生成器类型
        /// </summary>
        public Type SequenceGenerator
        {
            get { return Type.GetType(config.Generators.SequenceGenerator.Provider); }
            set { config.Generators.SequenceGenerator.Provider = value.AssemblyQualifiedName; }
        }
        /// <summary>
        /// 获取或设置对象容器类型
        /// </summary>
        public Type ObjectContainer
        {
            get { return Type.GetType(config.ObjectContainer.Provider); }
            set { config.ObjectContainer.Provider = value.AssemblyQualifiedName; }
        }

        /// <summary>
        /// 获取或设置一个 <see cref="System.Boolean"/> 值，标志配置文件application/web能否被对象容器初始化.
        /// </summary>
        public bool InitObjectContainerFromConfigFile
        {
            get { return config.ObjectContainer.InitFromConfigFile; }
            set { config.ObjectContainer.InitFromConfigFile = value; }
        }
        /// <summary>
        /// 获取或设置配置文件application/web中的配置结点能否被对象容器初始化
        /// </summary>
        public string ObjectContainerSectionName
        {
            get { return config.ObjectContainer.SectionName; }
            set { config.ObjectContainer.SectionName = value; }
        }
        #endregion

        #region Public Methods
 
        /// <summary>
        /// 添加一个异常定义到配置文件
        /// </summary>
        /// <param name="exceptionType">异常类型.</param>
        /// <param name="behavior">异常处理行为.</param>
        public void AddException(Type exceptionType, ExceptionHandlingBehavior behavior = ExceptionHandlingBehavior.Direct)
        {
            if (this.config.Exceptions == null)
                this.config.Exceptions = new ExceptionElementCollection();
            foreach (ExceptionElement ee in this.config.Exceptions)
            {
                if (ee.Type == exceptionType.AssemblyQualifiedName && ee.Behavior == behavior)
                    return;
            }
            this.config.Exceptions.Add(new ExceptionElement
            {
                Type = exceptionType.AssemblyQualifiedName,
                Behavior = behavior,
                Handlers = new ExceptionHandlerElementCollection()
            });
        }
        /// <summary>
        /// 添加一个异常处理到配置源
        /// </summary>
        /// <param name="exceptionType">将被处理的异常类型.</param>
        /// <param name="handlerType">异常处理类型.</param>
        public void AddExceptionHandler(Type exceptionType, Type handlerType)
        {
            foreach (ExceptionElement exceptionElement in this.config.Exceptions)
            {
                if (exceptionElement.Type.Equals(exceptionType.AssemblyQualifiedName))
                {
                    if (exceptionElement.Handlers == null)
                        exceptionElement.Handlers = new ExceptionHandlerElementCollection();
                    foreach (ExceptionHandlerElement exceptionHandlerElement in exceptionElement.Handlers)
                    {
                        if (exceptionHandlerElement.Type.Equals(handlerType.AssemblyQualifiedName))
                            return;
                    }
                    exceptionElement.Handlers.Add(new ExceptionHandlerElement
                    {
                        Type = handlerType.AssemblyQualifiedName
                    });
                }
            }
        }

        #region Interceptor
        /// <summary>
        /// 在当前配置源中添加一个拦截器
        /// </summary>
        /// <param name="name">拦截器名称.</param>
        /// <param name="interceptorType">拦截器类型.</param>
        public void AddInterceptor(string name, Type interceptorType)
        {
            if (!typeof(IInterceptor).IsAssignableFrom(interceptorType))
                throw new ConfigException("Type '{0}' is not an interceptor.", interceptorType);

            if (this.config.Interception == null)
                this.config.Interception = new InterceptionElement();
            if (this.config.Interception.Interceptors == null)
                this.config.Interception.Interceptors = new InterceptorElementCollection();
            foreach (InterceptorElement interceptor in this.config.Interception.Interceptors)
            {
                if (interceptor.Name.Equals(name) || interceptor.Type.Equals(interceptorType.AssemblyQualifiedName))
                    return;
            }
            var interceptorAdd = new InterceptorElement 
            {
                Name = name, 
                Type = interceptorType.AssemblyQualifiedName
            };
            this.config.Interception.Interceptors.Add(interceptorAdd);
        }
        /// <summary>
        /// 在指定的契约类型和方法上添加一个引用拦截器
        /// </summary>
        /// <param name="contractType">契约类型.</param>
        /// <param name="method">指定的方法.</param>
        /// <param name="name">引用拦截器名称.</param>
        public void AddInterceptorRef(Type contractType, MethodInfo method, string name)
        {
            if (this.config.Interception != null)
            {
                if (this.config.Interception.Contracts != null)
                {
                    foreach (InterceptContractElement interceptContract in this.config.Interception.Contracts)
                    {
                        if (interceptContract.Type.Equals(contractType.AssemblyQualifiedName))
                        {
                            if (interceptContract.Methods != null)
                            {
                                foreach (InterceptMethodElement interceptMethod in interceptContract.Methods)
                                {
                                    if (interceptMethod.Signature.Equals(method.GetSignature()))
                                    {
                                        if (interceptMethod.InterceptorRefs != null)
                                        {
                                            foreach (InterceptorRefElement interceptorRef in interceptMethod.InterceptorRefs)
                                            {
                                                if (interceptorRef.Name.Equals(name))
                                                    return;
                                            }
                                            interceptMethod.InterceptorRefs.Add(new InterceptorRefElement { Name = name });
                                        }
                                        else
                                        {
                                            interceptMethod.InterceptorRefs = new InterceptorRefElementCollection
                                                {
                                                    new InterceptorRefElement {Name = name}
                                                };
                                        }
                                        return;
                                    }
                                }
                                var interceptMethodAdd = new InterceptMethodElement
                                    {
                                        Signature = method.GetSignature(),
                                        InterceptorRefs = new InterceptorRefElementCollection
                                            {
                                                new InterceptorRefElement {Name = name}
                                            }
                                    };
                                interceptContract.Methods.Add(interceptMethodAdd);
                            }
                            else
                            {
                                interceptContract.Methods = new InterceptMethodElementCollection();
                                var interceptMethodAdd = new InterceptMethodElement
                                    {
                                        Signature = method.GetSignature(),
                                        InterceptorRefs = new InterceptorRefElementCollection
                                            {
                                                new InterceptorRefElement {Name = name}
                                            }
                                    };
                                interceptContract.Methods.Add(interceptMethodAdd);
                            }
                            return;
                        }
                    }
                    var interceptContractAdd = new InterceptContractElement
                        {
                            Type = contractType.AssemblyQualifiedName,
                            Methods = new InterceptMethodElementCollection()
                        };
                    var interceptMethodAddToContract = new InterceptMethodElement
                        {
                            Signature = method.GetSignature(),
                            InterceptorRefs = new InterceptorRefElementCollection {new InterceptorRefElement {Name = name}}
                        };
                    interceptContractAdd.Methods.Add(interceptMethodAddToContract);
                    this.config.Interception.Contracts.Add(interceptContractAdd);
                }
                else
                {
                    this.config.Interception.Contracts = new InterceptContractElementCollection();
                    var interceptContractAdd = new InterceptContractElement
                        {
                            Type = contractType.AssemblyQualifiedName,
                            Methods = new InterceptMethodElementCollection()
                        };
                    var interceptMethodAddToContract = new InterceptMethodElement
                        {
                            Signature = method.GetSignature(),
                            InterceptorRefs = new InterceptorRefElementCollection {new InterceptorRefElement {Name = name}}
                        };
                    interceptContractAdd.Methods.Add(interceptMethodAddToContract);
                    this.config.Interception.Contracts.Add(interceptContractAdd);
                }
            }
            else
            {
                this.config.Interception = new InterceptionElement
                    {
                        Contracts = new InterceptContractElementCollection()
                    };
                var interceptContractAdd = new InterceptContractElement
                    {
                        Type = contractType.AssemblyQualifiedName,
                        Methods = new InterceptMethodElementCollection()
                    };
                var interceptMethodAddToContract = new InterceptMethodElement
                    {
                        Signature = method.GetSignature(),
                        InterceptorRefs = new InterceptorRefElementCollection {new InterceptorRefElement {Name = name}}
                    };
                interceptContractAdd.Methods.Add(interceptMethodAddToContract);
                this.config.Interception.Contracts.Add(interceptContractAdd);
            }
        }
        #endregion

        #endregion

        #region IConfigSource Members
        /// <summary>
        /// 获得一个 <see cref="WisdomConfigSection"/> 类实例.
        /// </summary>
        public WisdomConfigSection Config
        {
            get { return this.config; }
        }

        #endregion
    }
}